package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"github.com/gin-gonic/gin"
	"github.com/satori/go.uuid"
	"time"
)

var (
	WebService *gin.Engine
	MqttClient mqtt.Client
	uid         = uuid.NewV4()
	broker      = ""
	username	= ""
	password	= ""
	httpAddr	= "0.0.0.0:80"
)

// 请求数据的结构体
type RequestData struct {
	Topic			string			`form:"topic"`
	Payload			interface{}		`form:"payload"`
}

// 响应数据的结构体
type ResponseData struct {
	Code		int		`form:"code"`
	Msg			string	`form:"msg"`
}

// 成功连接
var OnConnectHandler mqtt.OnConnectHandler = func(c mqtt.Client) {
	fmt.Println("Mqtt Broker connected")
}

// MQTT发送数据
func autoPublish(topic string, data interface{})(e error){

	if MqttClient.IsConnected() {
		if jsonBytes, e := json.Marshal(data); e == nil {
			token := MqttClient.Publish(topic, 0, false, string(jsonBytes))
			if !token.Wait(){
				e = errors.New("token Wait error")
			}
		}
	}

	return
}

func main() {
	flag.StringVar(&httpAddr, "addr", "0.0.0.0:80", "HTTP监听地址")
	flag.StringVar(&broker, "broker", "", "MQTT服务器地址,默认为空")
	flag.StringVar(&username, "username", "", "MQTT登录账号,默认为空")
	flag.StringVar(&password, "password", "", "MQTT登录密码,默认为空")
	//解析命令行参数
	flag.Parse()

	fmt.Println("addr : ", httpAddr)
	fmt.Println("broker : ", broker)
	fmt.Println("username : ", username)
	fmt.Println("password : ", password)

	// 连接 MQTT 代理服务器
	opts := mqtt.NewClientOptions().AddBroker(broker).SetClientID("WebMqttPusherr_" + uid.String())
	opts.SetOnConnectHandler(OnConnectHandler)
	opts.SetKeepAlive(5 * time.Second)
	opts.SetPingTimeout(1 * time.Second)
	opts.SetUsername(username)
	opts.SetPassword(password)
	opts.SetAutoReconnect(true)

	MqttClient = mqtt.NewClient(opts)
	if token := MqttClient.Connect(); token.Wait() && token.Error() != nil {
		fmt.Println("mqtt connect error:", token.Error())
		return
	}

	// 启动 HTTP 服务
	gin.SetMode("release")
	WebService = gin.New()
	WebService.Use(gin.Recovery())

	WebService.POST("/push", func(c *gin.Context) {
		code := 0
		result := "ok"

		requestData := new(RequestData)
		// 请求数据解释
		err := c.Bind(requestData)
		if err != nil {
			code = -1
			result = err.Error()

		} else {
			// 通过 MQTT 发送出去
			sendErr := autoPublish(requestData.Topic, requestData.Payload)
			if sendErr != nil {
				code = -1
				result = sendErr.Error()
			}
		}

		res := ResponseData{
			Code: code,
			Msg:  result,
		}

		c.IndentedJSON(200, res)
		return
	})

	// 如果启动失败（一般为端口被占用），则循环重启，间隔 3 秒
	for {
		if err := WebService.Run(httpAddr); err != nil{
			fmt.Println(err)
			time.Sleep(3 * time.Second)
		}
	}
}